﻿using System.Web;
using Cms.Application.WebFramework.Presenters;
using Cms.Web.Framework.Infrastructure.Wrappers;

namespace Cms.Web.Framework.Infrastructure
{
    public class RequestStartHandler
    {
        private readonly ICmsHttpRequest _request;
        private readonly ICmsHttpResponse _response;
        private readonly ICmsIdentity _identity;
        private readonly ICmsFormsAuthentication _formsAuthentication;
        private readonly ICmsHttpContextItems _contextItems;
        private RequestDetails _details;

        public RequestStartHandler(
            ICmsHttpRequest request, 
            ICmsHttpResponse response, 
            ICmsIdentity identity,
            ICmsFormsAuthentication formsAuthentication, 
            ICmsHttpContextItems contextItems)
        {
            _request = request;
            _response = response;
            _identity = identity;
            _formsAuthentication = formsAuthentication;
            _contextItems = contextItems;
        }

        public RequestDetailsPresenter UnitTestPresenter { get; set; }

        public void BeginRequest()
        {
            // Determine if we are in unit testing mode or not and create the correct version of RequestDetails accordingly
            _details = UnitTestPresenter == null ? new RequestDetails(_request, _identity) : new RequestDetails(_request, _identity, UnitTestPresenter);
            _contextItems.Add("RequestDetails", _details);
            if (_details.FoldersAndPage.ToLower() != "ssoauth.ashx" || _details.GetQueryStringValue("action") != "logout")
            {
                return;
            }
            SignOut();
        }

        private void SignOut()
        {
            _formsAuthentication.SignOut();
            string originDomain = null;

            // Add the current domain to the list of domains already logged out from 
            string alreadyLoggedOutDomains = _details.GetQueryStringValue("alreadyloggedoutdomains");
            if (alreadyLoggedOutDomains != string.Empty)
            {
                alreadyLoggedOutDomains += ",";
            }
            alreadyLoggedOutDomains += _details.SiteRootUrl;

            // Are there any sites left to log out from?
            string nextDomainToLogOutFrom = _details.Presenter.GetNextDomainToCheck(alreadyLoggedOutDomains);
            if (nextDomainToLogOutFrom != string.Empty)
            {
                _response.Redirect("http://" + nextDomainToLogOutFrom + "/ssoauth.ashx" +
                                                      "?action=logout" +
                                                      "&alreadyloggedoutdomains=" +
                                                      HttpUtility.UrlEncode(alreadyLoggedOutDomains));
            }
            else if (alreadyLoggedOutDomains != string.Empty)
            {
                originDomain = alreadyLoggedOutDomains.Split(",".ToCharArray())[0];
            }
            if (originDomain == null)
            {
                originDomain = _details.SiteRootUrl;
            }
            _response.Redirect("http://" + originDomain + "/admin/default.aspx");
        }

        public void AuthorizeRequest()
        {
            if (_identity.NoCurrentUser)
            {
                return;
            }
            if (RequestDoesNotRequireSingleSignOnAuthorization())
            {
                return;
            }
            if (!LoggedInOnThisSite() && SingleSignOnProcessNotCompleted())
            {
                ContinueToNextSite();
                return;
            }
            if (NoSingleSignOnRequest())
            {
                return;
            }
            if (LoggedInOnThisSite())
            {
                string url = "http://" + GetOriginalDomain() + "/Admin/Default.aspx" +
                             "?credentials=" + GetAdministratorCredentials() +
                             "&ReturnUrl=" + GetOriginalReturnUrl() +
                             "&ssoauth=completed";
                _response.Redirect(url);
            }
            else
            {
                ContinueToNextSite();
            }
        }

        private bool RequestDoesNotRequireSingleSignOnAuthorization()
        {
            return !_details.SingleSignOnAuthorizationRequired();
        }

        private bool LoggedInOnThisSite()
        {
            return _details.AdministratorID > 0;
        }

        private bool SingleSignOnProcessNotCompleted()
        {
            return _details.GetQueryStringValue("ssoauth") != "completed";
        }

        private bool NoSingleSignOnRequest()
        {
            return _details.FoldersAndPage.ToLower() != "ssoauth.ashx";
        }

        private string GetOriginalDomain()
        {
            return _details.GetQueryStringValue("alreadycheckeddomains").Split(",".ToCharArray())[0];
        }

        private string GetOriginalReturnUrl()
        {
            return HttpUtility.UrlEncode(_details.GetQueryStringValue("origin"));
        }

        private string GetAdministratorCredentials()
        {
            return HttpUtility.UrlEncode(_details.Presenter.GetAdministratorEncryptedCredentials(_details.AdministratorID));
        }

        private void ContinueToNextSite()
        {
            // Add the current domain to the list of already checked domains. 
            string alreadyCheckedDomains = _details.GetQueryStringValue("alreadycheckeddomains");
            if (alreadyCheckedDomains != string.Empty)
            {
                alreadyCheckedDomains += ",";
            }
            alreadyCheckedDomains += _details.SiteRootUrl;

            // Are there any sites left to check?
            string nextDomainToCheck = _details.Presenter.GetNextDomainToCheck(alreadyCheckedDomains);
            if (nextDomainToCheck != string.Empty)
            {
                string origin = _details.GetQueryStringValue("origin");
                if (origin == string.Empty)
                {
                    origin = _details.GetQueryStringValue("ReturnUrl");
                }
                _response.Redirect("http://" + nextDomainToCheck + "/ssoauth.ashx" +
                                                      "?origin=" + HttpUtility.UrlEncode(origin) +
                                                      "&alreadycheckeddomains=" +
                                                      HttpUtility.UrlEncode(alreadyCheckedDomains));
            }
            else if (alreadyCheckedDomains != string.Empty)
            {
                string originLogin = "http://" + alreadyCheckedDomains.Split(",".ToCharArray())[0] +
                                     "/admin/default.aspx" +
                                     "?ReturnUrl=" + GetOriginalReturnUrl() +
                                     "&ssoauth=completed";
                _response.Redirect(originLogin);
            }
        }
    }
}
